//===-- ClangTypeConverter.h - Converting Swift types to C types-*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file defines utilities for translating Swift types to C types.
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_AST_INTERNAL_CLANG_TYPE_CONVERTER_H
#define POLARPHP_AST_INTERNAL_CLANG_TYPE_CONVERTER_H

#include "polarphp/ast/AstContext.h"
#include "polarphp/ast/ClangModuleLoader.h"
#include "polarphp/ast/Type.h"
#include "polarphp/ast/TypeVisitor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"

namespace polar {

/// Compute C types corresponding to Swift AST types.
class ClangTypeConverter :
   public TypeVisitor<ClangTypeConverter, clang::QualType> {

   using super = TypeVisitor<ClangTypeConverter, clang::QualType>;

   llvm::DenseMap<Type, clang::QualType> Cache;

   bool StdlibTypesAreCached = false;

   AstContext &Context;

   clang::ASTContext &ClangASTContext;

   const llvm::Triple Triple;

   ClangTypeConverter(const ClangTypeConverter &) = delete;
   ClangTypeConverter &operator=(const ClangTypeConverter &) = delete;

public:

   /// Create a ClangTypeConverter.
   ClangTypeConverter(AstContext &ctx, clang::ASTContext &clangCtx,
                      llvm::Triple triple)
      : Context(ctx), ClangASTContext(clangCtx), Triple(triple)
   {
   };

   /// Compute the C function type for a Swift function type.
   ///
   /// It is the caller's responsibility to make sure this method is only
   /// called in the appropriate context. For example, it makes sense to use
   /// this method for the output type of a @convention(c) function.
   ///
   /// Since we do not check the context, the translation is unconditional.
   /// For example, String will automatically get translated to NSString
   /// when bridging is available.
   ///
   /// Additionally, the API is expected to be used only from
   ///
   /// \returns The appropriate clang type on success, nullptr on failure.
   ///
   /// Precondition: The representation argument must be C-compatible.
   const clang::Type *getFunctionType(
      ArrayRef<AnyFunctionType::Param> params, Type resultTy,
      AnyFunctionType::Representation repr);

private:
   clang::QualType convert(Type type);
   clang::QualType convertMemberType(NominalTypeDecl *DC,
                                     StringRef memberName);

   clang::QualType reverseBuiltinTypeMapping(StructType *type);

   friend TypeVisitor<ClangTypeConverter, clang::QualType>;

   clang::QualType visitStructType(StructType *type);
   clang::QualType visitTupleType(TupleType *type);
   clang::QualType visitMetatypeType(MetatypeType *type);
   clang::QualType visitExistentialMetatypeType(ExistentialMetatypeType *type);
   clang::QualType visitInterfaceType(InterfaceType *type);
   clang::QualType visitClassType(ClassType *type);
   clang::QualType visitBoundGenericClassType(BoundGenericClassType *type);
   clang::QualType visitBoundGenericType(BoundGenericType *type);
   clang::QualType visitEnumType(EnumType *type);
   clang::QualType visitFunctionType(FunctionType *type);
   clang::QualType visitInterfaceCompositionType(InterfaceCompositionType *type);
   clang::QualType visitBuiltinRawPointerType(BuiltinRawPointerType *type);
   clang::QualType visitBuiltinIntegerType(BuiltinIntegerType *type);
   clang::QualType visitBuiltinFloatType(BuiltinFloatType *type);
   clang::QualType visitArchetypeType(ArchetypeType *type);
   clang::QualType visitPILFunctionType(PILFunctionType *type);
   clang::QualType visitGenericTypeParamType(GenericTypeParamType *type);
   clang::QualType visitDynamicSelfType(DynamicSelfType *type);
   clang::QualType visitPILBlockStorageType(PILBlockStorageType *type);
   clang::QualType visitSugarType(SugarType *type);
   clang::QualType visitType(TypeBase *type);
   clang::QualType visit(Type type);
};

} // end namespace polar

#endif /* POLARPHP_AST_CLANG_TYPE_CONVERTER_H */
